/*
JuffEd - A simple text editor
Copyright 2007 Murzin Mikhail

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License 
version 2 as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include "HLStorage.h"

//	Local
#include "HL.h"

//	Qt
#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
#include <QtXml/QDomDocument>
#include <QtXml/QDomElement>
#include <QtXml/QDomNode>

void parseStyle(const QDomElement& el, QTextCharFormat& fmt) {
	QString boldStr = el.attribute("bold", "false").toLower();
	QString italicStr = el.attribute("italic", "false").toLower();
	QString colorStr = el.attribute("color", "#000000");
	fmt.setForeground(QVariant(colorStr).value<QColor>());
	if (boldStr.compare("true") == 0 || boldStr.compare("yes") == 0 || boldStr.compare("1") == 0) {
		fmt.setFontWeight(QFont::Bold);
	}
	if (italicStr.compare("true") == 0 || italicStr.compare("yes") == 0 || italicStr.compare("1") == 0) {
		fmt.setFontItalic(true);
	}
}

void parseRule(const QDomElement& el, QStringList& list, QTextCharFormat& fmt) {
	QDomNode itemNode = el.firstChild();
	while (!itemNode.isNull()) {
		QDomElement itemEl = itemNode.toElement();
		if (!itemEl.isNull()) {
			QString tagName = itemEl.tagName().toLower();
			if (tagName.compare("expr") == 0) {
				QString expr = itemEl.text().simplified();
				list << expr;
			}
			else if (tagName.compare("style") == 0) {
				parseStyle(itemEl, fmt);
			}
		}
		itemNode = itemNode.nextSibling();
	}
}

void parseScheme(const QDomElement& schEl, HLScheme& sch) {
	sch.name = schEl.attribute("name", "");
	sch.extensions = schEl.attribute("extensions", "").split(';');
	QDomNode ruleNode = schEl.firstChild();
	
	while (!ruleNode.isNull()) {
		QStringList exprList;
		HLRule rule;
		QDomElement ruleEl = ruleNode.toElement();
		QString ruleTagName = ruleEl.tagName().toLower();
		if (ruleTagName.compare("rule") == 0) {
			parseRule(ruleEl, exprList, rule.fmt);
			foreach (QString s, exprList) {
				rule.regExp = QRegExp(s);
				sch.rules_.append(rule);
			}
		}
		else if (ruleTagName.compare("comment") == 0) {
			QDomNode commNode = ruleEl.firstChild();
			while (!commNode.isNull()) {
				QDomElement commEl = commNode.toElement();
				QString tagName = commEl.tagName().toLower();
				if (tagName.compare("begin") == 0)
					sch.comment = commEl.text();
				else if (tagName.compare("style") == 0)
					parseStyle(commEl, sch.commentFmt);
				commNode = commNode.nextSibling();
			}
		}
		else if (ruleTagName.compare("block") == 0) {
			QDomNode blNode = ruleEl.firstChild();
			HLBlock blockRule;
			while (!blNode.isNull()) {
				QDomElement blEl = blNode.toElement();
				QString tagName = blEl.tagName().toLower();
				if (tagName.compare("begin") == 0)
					blockRule.begin = blEl.text();
				else if (tagName.compare("end") == 0)
					blockRule.end = blEl.text();
				else if (tagName.compare("style") == 0)
					parseStyle(blEl, blockRule.fmt);
				blNode = blNode.nextSibling();
			}
			sch.blocks_.append(blockRule);
		}
		ruleNode = ruleNode.nextSibling();
	}
}


///////////////////////////////////////////////////////////////////////
//	HLStorage
///////////////////////////////////////////////////////////////////////

HLStorage* HLStorage::st_ = 0;

HLStorage* HLStorage::instance() {
	if (st_ == 0) {
		st_ = new HLStorage();
		st_->readSchemes();
	}
	return st_;
}

bool HLStorage::readScheme(const QString& fileName, HLScheme& scheme) {
	QDomDocument doc("HLScheme");
	QFile file(fileName);
	if (QFileInfo(fileName).suffix().toLower().compare("xml") != 0 || !file.open(QIODevice::ReadOnly))
		return false;
	if (!doc.setContent(&file)) {
		file.close();
		return false;
	}
	file.close();

	QDomElement docElem = doc.documentElement();
	QDomNode schNode = docElem.firstChild();
	while(!schNode.isNull()) {
		QDomElement schEl = schNode.toElement();
		if(!schEl.isNull()) {
			if (schEl.tagName().toLower().compare("scheme") == 0) {
				parseScheme(schEl, scheme);
			}
		}
		schNode = schNode.nextSibling();
	}
	return true;
}

void HLStorage::readSchemes() {
	QDir localDir(QDir::home().absolutePath() + "/.config/juff/hlschemes");
	QDir globalDir(QCoreApplication::applicationDirPath() + "/hlschemes");
	QString localPath = localDir.absolutePath();
	QString globalPath = globalDir.absolutePath();

	if (!localDir.exists())
		localDir.mkpath(localPath);
	if (localDir.entryList(QDir::Files).isEmpty()) {
		foreach (QString fileName, globalDir.entryList(QDir::Files))
			QFile::copy(globalPath + "/" + fileName, localPath + "/" + fileName);
	}

	//	read schemes
	foreach (QString schemeFile, localDir.entryList(QDir::Files)) {
		HLScheme scheme;
		if (readScheme(localPath + "/" + schemeFile, scheme)) {
			schemes_.append(scheme);
		}
	}
}

bool HLStorage::getScheme(const QString& name, HLScheme& sch) {
	bool res = false;
	QString ext = QFileInfo(name).suffix();
	foreach (HLScheme scheme, schemes_) {
		if (scheme.extensions.contains(ext)) {
			sch = scheme;
			res = true;
			break;
		}
	}
	return res;
}
